﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.Text;

namespace BrettM.Commands
{


    public class ExecuteResult
    {
        public ExecuteResult()
        {
            this.Status = ExecuteResultStatus.Success;
            this.Errors = new CommandResults();
        }

        public ExecuteResultStatus Status { get; set; }
        public CommandResults Errors { get; private set; }

        public IEnumerable<S> GetErrors<S>()
        {
            return this.Errors.Where(e => e is S).Cast<S>().ToList();
        }


        public void AddException(Exception ex)
        {
            this.Status = ExecuteResultStatus.Failure;
            this.Errors.Add(new CommandException(ex.Message, ex));
        }

        public static ExecuteResult operator +(ExecuteResult lhs, ExecuteResult rhs)
        {
            var result = new ExecuteResult();

            if (lhs != null)
            {
                result.Status = lhs.Status;
                foreach (var item in lhs.Errors)
                {
                    result.Errors.Add(item);
                }

            }

            if (rhs != null)
            {
                if (result.Status != rhs.Status)
                {
                    if (rhs.Status == ExecuteResultStatus.Failure)
                    {
                        result.Status = ExecuteResultStatus.Failure;
                    }
                    else if (lhs.Status == ExecuteResultStatus.Success && rhs.Status == ExecuteResultStatus.Warnings)
                    {
                        result.Status = ExecuteResultStatus.Warnings;
                    }
                }
                foreach (var item in rhs.Errors)
                {
                    result.Errors.Add(item);
                }

            }

            return result;
        }


        public void AddWarning(string p)
        {
            if (this.Status != ExecuteResultStatus.Failure)
            {
                this.Status = ExecuteResultStatus.Warnings;
            }
        }

        public void AddError(string p)
        {
            this.Status = ExecuteResultStatus.Failure;
            var error = new CommandError(p);
            //TODO:  Add more information to this stack trace
            StackTrace stack = new StackTrace();
            StackFrame[] frames = stack.GetFrames();
            var sb = new StringBuilder();
            foreach (var frame in frames)
            {
                sb.AppendFormat("{0}\r\n", frame.GetMethod().Name);
            }
            error.StackTrace = sb.ToString();
            // Add the error to the list of errors.
            this.Errors.Add(error);
        }
    }

    /// <summary>
    /// All commands
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ExecuteResult<T> 
        : ExecuteResult
    {
        public ExecuteResult()
            : base()
        {
            this.Item = default(T);
        }


        public ExecuteResult(T item)
        {
            this.Item = item;
            this.Status = ExecuteResultStatus.Success;
        }

        public T Item { get; set; }


        public static ExecuteResult<T> operator +(ExecuteResult<T> lhs, ExecuteResult rhs)
        {
            var result = new ExecuteResult<T>();

            if (lhs != null)
            {
                result.Status = lhs.Status;
                result.Item = lhs.Item;
                foreach (var item in lhs.Errors)
                {
                    result.Errors.Add(item);
                }
            }

            if (rhs != null)
            {
                if (result.Status != rhs.Status)
                {
                    if (rhs.Status == ExecuteResultStatus.Failure)
                    {
                        result.Status = ExecuteResultStatus.Failure;
                    }
                    else if (lhs.Status == ExecuteResultStatus.Success && rhs.Status == ExecuteResultStatus.Warnings)
                    {
                        result.Status = ExecuteResultStatus.Warnings;
                    }
                }
                foreach (var item in rhs.Errors)
                {
                    result.Errors.Add(item);
                }

            }

            return result;
        }
       
    }
}
